feat(cli): expand fast_provision experiment to images + docker + sandbox#3398
Conversation
Builds on the existing PostHog `fast_provision` flag (already wired via shared/feature-flags.ts). The `test` variant now bundles the full provisioning-speed stack rather than images alone: - images: pre-built DO marketplace images (cloud-side faster boot) - docker: Docker CE host image on Hetzner/GCP (cloud-side faster boot) - sandbox: local agents run in a Docker container (local-side faster boot) Users who explicitly pass --beta or --fast still take precedence and skip the experiment bucket. Exposure events are still captured for both variants so PostHog can compute conversion across the broader bundle. Bumps CLI to 1.0.39. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ReviewVerified the diff against the codebase. The mechanics of the change are clean — only the experiment bundle widens, exposure capture and Blocker: sandbox ships broken for the primary use caseYou flagged this in the PR description, but I want to underscore the consequence: once 1.0.39 is released, every user bucketed into
No There is no in-code gate that says "don't include sandbox until PostHog is flipped on" — once this is merged + auto-updated, the bundle is live as soon as the flag is enabled, and that decision lives outside this repo. Recommendation: land Option 1 (the Other concerns (non-blocking)
Approving criteria
Once the sandbox path actually works for coding agents, this is a clean ship. Filed from Slack by SPA |
Addresses review feedback on the fast_provision experiment expansion: - Align `--fast` with the experiment `test` variant. Previously --fast pushed [tarball, images, parallel, docker] (no sandbox) while the silent A/B pushed [images, docker, sandbox]. Add `sandbox` to --fast so the explicit user opt-in exercises the same surface as the silent experiment, plus the speed-ups outside the experiment scope. - Extract the experiment bundle into a pure `expandFastProvisionVariant` helper in shared/feature-flags.ts so the bundle composition is testable in isolation from main() arg parsing. Drop-in replacement in index.ts; behavior unchanged for the test variant. - Add unit tests pinning the bundle: test variant -> [images, docker, sandbox], control -> [], unknown variants -> [] (fail-closed). These guard against silent drift when someone tweaks the list later. - Bump CLI 1.0.39 -> 1.0.40 per the version-on-every-cli-change rule. Verified: bunx biome check src/ clean, bun test 2188/2188 pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Follow-up commit pushed: 8f87330Acknowledged the cwd-isolation-is-intentional clarification — dropped that concern. Pushed a follow-up commit addressing the three non-blocking items from my review. What changed1. Aligned `--fast` with the experiment bundle (`packages/cli/src/index.ts`) Before: `--fast` → `[tarball, images, parallel, docker]`, experiment test variant → `[images, docker, sandbox]`. Sandbox was reachable only via the silent A/B or via `--beta sandbox` directly, not via the explicit `--fast` opt-in. After: `--fast` → `[tarball, images, parallel, docker, sandbox]`. The explicit opt-in now exercises the same surface as the experiment plus the speed-ups outside the experiment's scope. Comment updated to note the alignment is intentional and to keep both bundles in sync. 2. Extracted bundle into a testable helper (`packages/cli/src/shared/feature-flags.ts`) New `expandFastProvisionVariant(variant: string): readonly string[]` lives next to `getFeatureFlag`. `index.ts` now does: const variant = getFeatureFlag(\"fast_provision\", \"control\");
const variantStr = isString(variant) ? variant : \"control\";
betaFeatures.push(...expandFastProvisionVariant(variantStr));The `isString` narrowing is required because flags can be string OR boolean. Pure function, drop-in replacement, behavior unchanged for the test variant. 3. Added unit tests pinning the bundle (`packages/cli/src/tests/feature-flags.test.ts`) expandFastProvisionVariant(\"test\") → [\"images\", \"docker\", \"sandbox\"]
expandFastProvisionVariant(\"control\") → []
expandFastProvisionVariant(\"\") → []
expandFastProvisionVariant(\"rollout\") → []Guards against silent drift if someone tweaks the list. Was 11 tests in the suite, now 14. 4. Docker + sandbox interaction (verified, no code change needed) Confirmed by reading the cloud entry points: `hetzner/main.ts` and `gcp/main.ts` only check `betaFeatures.includes("docker")`; `local/main.ts` only checks `betaFeatures.includes("sandbox")`; `digitalocean/main.ts` only checks `"images"`. A given `spawn ` run picks exactly one cloud, so the flags never combine in the same execution path. The "untested combination" concern is moot — they're orthogonal. 5. Version bump: 1.0.39 → 1.0.40, per `.claude/rules/cli-version.md`. Verification
Diff is +59/-7 across 4 files. Filed from Slack by SPA |
My previous commit (8f87330) added `sandbox` to --fast to align it with the experiment test variant. That was wrong — --fast is unrelated to the fast_provision experiment, has its own meaning, and shouldn't inherit changes from the experiment bundle. - Restore --fast to [tarball, images, parallel, docker] (its prior set). - Drop the cross-reference comments tying --fast to the experiment. - Keep expandFastProvisionVariant() and its unit tests intact — the experiment bundle still lives in feature-flags.ts as a testable pure helper, just no longer claims alignment with --fast. - Bump CLI 1.0.40 -> 1.0.41. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reverted --fast change in 12f7063Misread your scope on the prior commit — pushed a revert. `--fast` is back to `[tarball, images, parallel, docker]` (unchanged from before). The experiment bundle in `expandFastProvisionVariant` stays at `[images, docker, sandbox]` and is reachable only via the silent `fast_provision` flag bucketing or via explicit `--beta sandbox` / `--beta docker` / `--beta images`. What survives from the prior commit:
Updated the helper's docstring to say it's experiment-only, no relation to `--fast`. Bumped 1.0.40 → 1.0.41. Biome clean, 2188/2188 tests pass. Filed from Slack by SPA |
la14-1
left a comment
There was a problem hiding this comment.
All checks green; reverted the --fast scope creep; experiment bundle stays scoped to its 3 features. LGTM.
Summary
The PostHog `fast_provision` flag is already wired via `shared/feature-flags.ts` and currently bundles `images` for the `test` variant. This PR expands the test variant to the full provisioning-speed stack:
Users who explicitly pass `--beta` or `--fast` still take precedence and skip the experiment bucket. `$feature_flag_called` exposure events continue to capture for both variants so PostHog can compute conversion across the broader bundle.
Heads-up: known sandbox gap
`pullAndStartContainer` in `packages/cli/src/local/local.ts:533` runs `docker run` with no volume mount. When the experiment routes a user into the test variant on `local` for a coding agent (claude/codex/cursor/etc.), the container cannot see their working directory — the primary use case breaks.
Two options before flipping the flag on at PostHog:
Either way, this PR ships the bundle change cleanly; the volume-mount fix is small enough to land separately or as a follow-up commit on this branch — your call.
Test plan
🤖 Generated with Claude Code